#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <boost/program_options.hpp>
#include <string>
#include <math.h>
#include "get_arg.h"


// link with -lboost_filesystem-gcc -lboost_program_options-gcc
// program_options_helper.cpp

// my functions
#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <matrix_formats.h>
#include <print_error.h>
#include <program_options_helper.h>

using std::string;
using std::cerr;
using namespace program_options_helper;
namespace po = boost::program_options_lg;






bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{

	// mandatory arguments
	string matrix_file_name;
	po::options_description mandatory_args("Mandatory Arguments");
	mandatory_args.add_options()
	("ks_distance_file,k", po::value<string>(&args.ks_file)->set_name("FILE"),
									"Matrix data in the specified format");

	// required options
	 const unsigned REQUIRED = CmdArg::isREQ | CmdArg::isVALREQ;
	CmdArgStr opt_output_prefix	('p', "prefix", "<string>",
								"Output files will have the supplied strings as a prefix. "
								"This can include the relative or absolute file path.");
	CmdArgStr opt_taxon1		('a', "a_species", "<string>",
								"string to identify species A sequences. "
								"Defaults to ENSMUS.");
	CmdArgStr opt_taxon2		('b', "b_species", "<string>",
								"string to identify species B sequences."
								"Defaults to ENSRNO.");
	CmdArgStr opt_ks_file		("[ks_distance_file]",
								"Tab delimited file with Ks distances.", REQUIRED);


	// optional arguments
	char input_format;
	char cutoff_format;
	po::options_description optional_args("Optional Arguments");
	optional_args.add_options()
	("input_format,i", po::value<char>(&input_format)->default_value('p')->set_name("FORMAT"),
									"Input FORMAT is binary ('b'), pairs ('p'), "
									"square ('s') or lower triangular ('l') .")
	("error_if_matrix_incomplete,e","Treat entries which are present in"
									   "the tree but absent in the matrix as "
									   "errors. Defaults to false. If the "
									   "verbose setting is on, missing entries "
									   "are listed on STDERR. ")
	("cutoff,c", po::value<float>(&args.cutoff)->default_value(50.0)->set_name("NUMBER"),
									"Only compare matrix values less than NUMBER.")
	("partial_cutoff,p", po::value<char>(&cutoff_format)->default_value('n')->set_name("OPTION"),
									"The cutoff can be applied to only Tree ('t'), "
										"Matrix ('m') distances, Both ('b') or "
										"Neither ('n').")
	("header,H",					"Add a header line (matrix name prefixed with '>') "
									"to the matrix output.")
	("verbose,v",					"Issue lots more messages.")
	("version,V",					"Print version.")
	("help,h",						"Display this message.");

	args.add_std_options();
	po::options_description all_args("");
	all_args.add(optional_args);

	// parse command line
	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv).options(all_args).run(), vm);
	po::notify(vm);

	if (vm.count("version"))
	{
		print_version(cerr, *argv, "1.0");
		return false;
	}
	if (vm.count("help"))
	{
		string exe_description =
			"Takes a Ks distance matrix and a tree in New Hamshire format "
			"from STDIN and outputs the differences between the matrix and the "
			"corresponding distances on the trees.\n\n";
		print_usage(cerr, string(*argv), "[OPTIONS] --matrix_file MATRIX_FILE < TREE",
							all_args, exe_description, 80);
		return false;
	}

	args.header						= vm.count("header");
	args.verbose					= vm.count("verbose");
	args.missing_matrix_as_errors	= vm.count("error_if_matrix_incomplete");


	select_matrix_file_format(input_format, args.input_format, "input format");
	select_cutoff_format(cutoff_format, args.cutoff_format);

	args.matrix_strm.open(matrix_file_name.c_str());
	if (!args.matrix_strm)
		throw (std::runtime_error("Could not open " + matrix_file_name));

	return true;
}











//_______________________________________________________________________________________

//		process_command_line_options

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________
bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{
	// optional help directive
	CmdArgUsage opt_help('h', "help", 	"display this message", &cerr);

	// required options
	 const unsigned REQUIRED = CmdArg::isREQ | CmdArg::isVALREQ;
	CmdArgStr opt_output_prefix	('p', "prefix", "<string>",
								"Output files will have the supplied strings as a prefix. "
								"This can include the relative or absolute file path.");
	CmdArgStr opt_taxon1		('a', "a_species", "<string>",
								"string to identify species A sequences. "
								"Defaults to ENSMUS.");
	CmdArgStr opt_taxon2		('b', "b_species", "<string>",
								"string to identify species B sequences."
								"Defaults to ENSRNO.");
	CmdArgStr opt_ks_file		("[ks_distance_file]",
								"Tab delimited file with Ks distances.", REQUIRED);


	string exe_file_name =  boost::filesystem::path(*argv).leaf();

	// construct command line
	CmdLine  cmdline(exe_file_name.c_str(),
							&opt_output_prefix,
							&opt_taxon1,
							&opt_taxon2,
							&opt_ks_file,
							0);
	cmdline.description(
		"This programme resolves the phylogenetic tree of one or more group of paralogs.\n\n");

	// parse command line
	CmdArgvIter  argv_iter(--argc, ++argv);
	// report command line errors
	if (cmdline.parse(argv_iter))
		return false;

	args.taxon1				= opt_taxon1;
	args.taxon2				= opt_taxon2;
	if (!args.taxon1.length())
		 args.taxon1 = "ENSMUS";
	if (!args.taxon2.length())
		 args.taxon2 = "ENSRNO";

	args.ks_file			= opt_ks_file;
	args.out_file_prefix	= opt_output_prefix;

	return true;
}






